package cn.woochen.comlib

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import com.kingja.loadsir.core.LoadService
import com.kingja.loadsir.core.LoadSir
import cn.woochen.comlib.config.IBaseView
import cn.woochen.comlib.loadinglayout.EmptyCallBack
import cn.woochen.comlib.loadinglayout.ErrorCallback
import cn.woochen.comlib.loadinglayout.LoadingCallBack
import cn.woochen.comlib.loadinglayout.LoadingHasContentCallBack
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type

abstract class BaseFragment<DB: ViewDataBinding,VM: BaseViewModel> :Fragment(), IBaseView {

    protected  val mContext by lazy {
        requireActivity()
    }

    protected lateinit var mBinding: DB
        private set

    protected lateinit var mViewModel:VM

    protected lateinit var loadService: LoadService<*>

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        mBinding =  DataBindingUtil.inflate(inflater, setContentView(), container, false)
        mViewModel = createViewModel()
//        loadService = LoadSir.getDefault().register((mBinding.root as ViewGroup).getChildAt(0))
        loadService = LoadSir.getDefault().register(mBinding.root)
        registerNecessaryObserver()
        initListener()
        initData()
//        return mBinding.root
        return loadService.loadLayout
    }

    private fun createViewModel ():VM{
        return  ViewModelProvider(this).get(getVmClazz(this))
    }

    protected abstract fun setContentView(): Int

    protected open fun initListener() {}

    /**
     * 获取任意对象的泛型信息，返回一个继承了BaseViewModel的字节码对象
     */
    private  fun getVmClazz(obj:Any): Class<VM> {
        var cls: Class<*>? = obj.javaClass
        var vmClass: Class<VM>? = null
        while (vmClass == null && cls != null) {
            vmClass = getVMClass(cls)
            cls = cls.superclass
        }
        if (vmClass == null) {
            vmClass = BaseViewModel::class.java as Class<VM>
        }
        return vmClass
    }

    private  fun getVMClass(cls: Class<*>): Class<VM>? {
        val type: Type? = cls.genericSuperclass
        if (type is ParameterizedType) {
            val types: Array<Type> = type.actualTypeArguments
            for (t in types) {
                if (t is Class<*>) {
                    val vmClass = t
                    if (BaseViewModel::class.java.isAssignableFrom(vmClass)) {
                        return vmClass as Class<VM>
                    }
                } else if (t is ParameterizedType) {
                    val rawType: Type = t.rawType
                    if (rawType is Class<*>) {
                        val vmClass = rawType
                        if (BaseViewModel::class.java.isAssignableFrom(vmClass)) {
                            return vmClass as Class<VM>
                        }
                    }
                }
            }
        }
        return null
    }

    /**
     * 网络请求数据
     */
    protected open fun requestData() {}

    protected abstract fun initData()

    override fun showContent() {
        loadService.showSuccess()
    }

    override fun showEmpty() {
        loadService.showCallback(EmptyCallBack::class.java)
    }

    override fun showLoading(showContent: Boolean) {
      /*  if (showContent) {
            loadService.showCallback(LoadingHasContentCallBack::class.java)
        } else {
            loadService.showCallback(LoadingCallBack::class.java)
        }*/
    }

    override fun showError() {
        loadService.showCallback(ErrorCallback::class.java)
    }

    /**
     * 注册 UI 事件
     */
    protected open fun registerNecessaryObserver() {
        mViewModel.loadingChange.showDialog.observe(this, Observer {
            showLoading(true)
        })
        mViewModel.loadingChange.dismissDialog.observe(this, Observer {
            showContent()
        })
    }

}